/*
 * Copyright (c) 2019.  drakelee.base All rights reserved.
 */

package com.base.components.database.service;

import com.base.components.database.dao.base.GenericJpaDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.io.Serializable;
import java.util.List;

/**
 * @param <T> 实体类
 * @param <ID> 实体类ID
 *
 * @author DLee
 * @version V1.0
 * @Description 实现service(JPAGenericInterfaceService)中通用的CRUD方法和一些工具方法, 各service的实现类需继承此类
 * @date 2015年9月5日 下午3:12:09
 */
public abstract class AbstractJpaService<T extends Serializable, ID extends Serializable, Dao extends GenericJpaDao<T, ID>> 
  implements JpaService<T, ID> {

  private volatile JpaEntityInformation<T, ?> entityInformation;

  @PersistenceContext
  private EntityManager entityManager;

  protected AbstractJpaService() {
  }

  protected EntityManager getEntityManager(){
    return this.entityManager;
  }

  protected JpaEntityInformation<T, ?> getEntityInformation() {
    if(this.entityInformation == null){
      this.entityInformation = getDao().getEntityInformation();
    }
    return this.entityInformation;
  }

  /**
   * 获取具体Dao实现
   *
   * @return GenericJpaDao
   */
  @Autowired
  private Dao jpaDao;

  protected Dao getDao(){
    return jpaDao;
  }
  
  @Override
  public List<T> findAll() {
    return getDao().findAll();
  }
  @Override
  public List<T> findAll(Sort paramSort) {
    return getDao().findAll(paramSort);
  }
  @Override
  public List<T> findAllById(Iterable<ID> paramIterable) {
    return getDao().findAllById(paramIterable);
  }
  @Override
  public T getOne(ID paramID) {
    return getDao().getOne(paramID);
  }
  @Override
  public long count(Specification<T> paramSpecification) {
    return getDao().count(paramSpecification);
  }
  @Override
  public T findById(ID paramID) {
    return getDao().findById(paramID).orElse(null);
  }
  @Override
  public boolean existsById(ID paramID) {
    return getDao().existsById(paramID);
  }
  @Override
  public long count() {
    return getDao().count();
  }
  @Override
  public Page<T> findAll(Pageable paramPageable) {
    return getDao().findAll(paramPageable);
  }
  @Override
  public T findOne(Specification<T> paramSpecification) {
    return getDao().findOne(paramSpecification).orElse(null);
  }
  @Override
  public List<T> findAll(Specification<T> paramSpecification) {
    return getDao().findAll(paramSpecification);
  }
  @Override
  public Page<T> findAll(Specification<T> paramSpecification, Pageable paramPageable) {
    return getDao().findAll(paramSpecification, paramPageable);
  }
  @Override
  public List<T> findAll(Specification<T> paramSpecification, Sort paramSort) {
    return getDao().findAll(paramSpecification, paramSort);
  }
  @Override
  public <S extends T> Iterable<S> saveAll(Iterable<S> entities){
    return getDao().saveAll(entities);
  }
  @Override
  public <S extends T> S save(S entity){
    return getDao().save(entity);
  }
  @Override
  public <S extends T> S saveAndFlush(S entity){
    return getDao().saveAndFlush(entity);
  }
  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean deleteById(ID id) {
    if(id != null){
      JpaEntityInformation<T, ?> information = getEntityInformation();
      Iterable<String> idAttributeNames = information.getIdAttributeNames();
      if(idAttributeNames.iterator().hasNext()){
        String idName = idAttributeNames.iterator().next();
        int count = getEntityManager()
          .createQuery("delete from " + information.getEntityName() + " where " + idName + " = :id")
          .setParameter("id", id).executeUpdate();
        return count > 0;
      }
    }
    return false;
  }
  @Override
  @Transactional(rollbackFor = Exception.class)
  public int deleteInBatch(Iterable<ID> ids) {
    if(ids.iterator().hasNext()){
      JpaEntityInformation<T, ?> information = getEntityInformation();
      Iterable<String> idAttributeNames = information.getIdAttributeNames();
      if(idAttributeNames.iterator().hasNext()){
        String idName = idAttributeNames.iterator().next();
        return getEntityManager()
          .createQuery("delete from " + information.getEntityName() + " where " + idName + " in (:ids)")
          .setParameter("ids", ids).executeUpdate();
      }
    }
    return 0;
  }
}
